home *** CD-ROM | disk | FTP | other *** search
- #include <stdio.h>
- #include "c.h"
- #include "expr.h"
- #include "gen.h"
- #include "cglbdec.h"
-
- /*
- * 68000 C compiler
- *
- * Copyright 1984, 1985, 1986 Matthew Brandt.
- * all commercial rights reserved.
- *
- * This compiler is intended as an instructive tool for personal use. Any
- * use for profit without the written consent of the author is prohibited.
- *
- * This compiler may be distributed freely for non-commercial use as long
- * as this notice stays intact. Please forward any enhancements or questions
- * to:
- *
- * Matthew Brandt
- * Box 920337
- * Norcross, Ga 30092
- */
-
- /*
- * this module contains all of the code generation routines
- * for evaluating expressions and conditions.
- */
-
- extern struct amode push[], pop[];
-
- struct amode *gen_expr(); /* forward declaration */
-
- struct amode *make_label(lab)
- /*
- * construct a reference node for an internal label number.
- */
- int lab;
- { struct enode *lnode;
- struct amode *ap;
- lnode = xalloc(sizeof(struct enode));
- lnode->nodetype = en_labcon;
- lnode->v.i = lab;
- ap = xalloc(sizeof(struct amode));
- ap->mode = am_direct;
- ap->offset = lnode;
- return ap;
- }
-
- struct amode *make_immed(i)
- /*
- * make a node to reference an immediate value i.
- */
- int i;
- { struct amode *ap;
- struct enode *ep;
- ep = xalloc(sizeof(struct enode));
- ep->nodetype = en_icon;
- ep->v.i = i;
- ap = xalloc(sizeof(struct amode));
- ap->mode = am_immed;
- ap->offset = ep;
- return ap;
- }
-
- struct amode *make_offset(node)
- /*
- * make a direct reference to a node.
- */
- struct enode *node;
- { struct amode *ap;
- ap = xalloc(sizeof(struct amode));
- ap->mode = am_direct;
- ap->offset = node;
- return ap;
- }
-
- make_legal(ap,flags,size)
- /*
- * make_legal will coerce the addressing mode in ap1 into a
- * mode that is satisfactory for the flag word.
- */
- struct amode *ap;
- int flags, size;
- { struct amode *ap2;
- if( ((flags & F_VOL) == 0) || ap->tempflag )
- {
- switch( ap->mode )
- {
- case am_immed:
- if( flags & F_IMMED )
- return; /* mode ok */
- break;
- case am_areg:
- if( flags & F_AREG )
- return;
- break;
- case am_dreg:
- if( flags & F_DREG )
- return;
- break;
- case am_ind: case am_indx:
- case am_indx2: case am_xpc:
- case am_direct: case am_indx3:
- if( flags & F_MEM )
- return;
- break;
- }
- }
- if( flags & F_DREG )
- {
- freeop(ap); /* maybe we can use it... */
- ap2 = temp_data(); /* allocate to dreg */
- gen_code(op_move,size,ap,ap2);
- ap->mode = am_dreg;
- ap->preg = ap2->preg;
- ap->deep = ap2->deep;
- ap->tempflag = 1;
- return;
- }
- if( size == 1 )
- {
- freeop(ap);
- ap2 = temp_data();
- gen_code(op_move,1,ap,ap2);
- gen_code(op_ext,2,ap2,0);
- freeop(ap);
- ap->mode = ap2->mode;
- ap->preg = ap2->preg;
- ap->deep = ap2->deep;
- size = 2;
- }
- freeop(ap);
- ap2 = temp_addr();
- gen_code(op_move,size,ap,ap2);
- ap->mode = am_areg;
- ap->preg = ap2->preg;
- ap->deep = ap2->deep;
- ap->tempflag = 1;
- }
-
- do_extend(ap,isize,osize,flags)
- /*
- * if isize is not equal to osize then the operand ap will be
- * loaded into a register (if not already) and if osize is
- * greater than isize it will be extended to match.
- */
- struct amode *ap;
- int isize, osize, flags;
- { if( isize == osize )
- return;
- if( ap->mode != am_areg && ap->mode != am_dreg )
- make_legal(ap,flags & (F_AREG | F_DREG),isize);
- if( ap->mode == am_areg )
- return; /* extend is automagic */
- switch( isize )
- {
- case 1:
- gen_code(op_ext,2,ap,0);
- case 2:
- if( osize == 4 )
- gen_code(op_ext,4,ap,0);
- }
- }
-
- int isshort(node)
- /*
- * return true if the node passed can be generated as a short
- * offset.
- */
- struct enode *node;
- { return node->nodetype == en_icon &&
- (node->v.i >= -65536 && node->v.i <= 65535);
- }
-
- int isbyte(node)
- /*
- * return true if the node passed can be evaluated as a byte
- * offset.
- */
- struct enode *node;
- { return node->nodetype == en_icon &&
- (-128 <= node->v.i && node->v.i <= 127);
- }
-
- struct amode *gen_index(node)
- /*
- * generate code to evaluate an index node (^+) and return
- * the addressing mode of the result. This routine takes no
- * flags since it always returns either am_ind or am_indx.
- */
- struct enode *node;
- { struct amode *ap1, *ap2;
- if( node->v.p[0]->nodetype == en_tempref &&
- node->v.p[1]->nodetype == en_tempref &&
- ( node->v.p[0]->v.i >= 8 || node->v.p[1]->v.i >= 8 ))
- { /* both nodes are registers, one is address */
- if( node->v.p[0]->v.i < 8 )
- {
- ap1 = gen_expr(node->v.p[1],F_AREG,4);
- ap1->sreg = node->v.p[0]->v.i;
- ap1->mode = am_indx2; /* 0(Ax,Dx) */
- ap1->offset = makenode(en_icon,0,0);
- return ap1;
- }
- ap1 = gen_expr(node->v.p[0],F_AREG,4);
- ap2 = gen_expr(node->v.p[1],F_AREG | F_DREG,4);
- if( ap2->mode == am_dreg )
- {
- ap1->mode = am_indx2;
- ap1->sreg = ap2->preg;
- }
- else
- {
- ap1->mode = am_indx3;
- ap1->sreg = ap2->preg;
- }
- ap1->offset = makenode(en_icon,0,0);
- return ap1;
- }
- ap1 = gen_expr(node->v.p[0],F_AREG | F_IMMED,4);
- if( ap1->mode == am_immed && isshort(ap1->offset) )
- {
- ap2 = gen_expr(node->v.p[1],F_AREG,4);
- ap2->mode = am_indx;
- ap2->offset = ap1->offset;
- return ap2;
- }
- ap2 = gen_expr(node->v.p[1],F_ALL,4); /* get right op */
- if( ap2->mode == am_immed && isshort(ap2->offset) &&
- ap1->mode == am_areg ) /* make am_indx */
- {
- ap2->mode = am_indx;
- ap2->preg = ap1->preg;
- ap2->deep = ap1->deep;
- return ap2;
- }
- validate(ap1);
- make_legal(ap1,F_AREG | F_VOL,4);
- gen_code(op_add,4,ap2,ap1); /* add left to address reg */
- ap1->mode = am_ind; /* make indirect */
- freeop(ap2); /* release any temps in ap2 */
- return ap1; /* return indirect */
- }
-
- struct amode *gen_deref(node,flags,size)
- /*
- * return the addressing mode of a dereferenced node.
- */
- struct enode *node;
- int flags, size;
- { struct amode *ap1;
- int siz1;
- switch( node->nodetype ) /* get load size */
- {
- case en_b_ref:
- siz1 = 1;
- break;
- case en_w_ref:
- siz1 = 2;
- break;
- case en_l_ref:
- siz1 = 4;
- break;
- }
- if( node->v.p[0]->nodetype == en_add )
- {
- ap1 = gen_index(node->v.p[0]);
- do_extend(ap1,siz1,size,flags);
- make_legal(ap1,flags,size);
- return ap1;
- }
- else if( node->v.p[0]->nodetype == en_autocon )
- {
- ap1 = xalloc(sizeof(struct amode));
- ap1->mode = am_indx;
- ap1->preg = 6;
- ap1->offset = makenode(en_icon,node->v.p[0]->v.i);
- do_extend(ap1,siz1,size,flags);
- make_legal(ap1,flags,size);
- return ap1;
- }
- ap1 = gen_expr(node->v.p[0],F_AREG | F_IMMED,4); /* generate address */
- if( ap1->mode == am_areg )
- {
- ap1->mode = am_ind;
- do_extend(ap1,siz1,size,flags);
- make_legal(ap1,flags,size);
- return ap1;
- }
- ap1->mode = am_direct;
- do_extend(ap1,siz1,size,flags);
- make_legal(ap1,flags,size);
- return ap1;
- }
-
- struct amode *gen_unary(node,flags,size,op)
- /*
- * generate code to evaluate a unary minus or complement.
- */
- struct enode *node;
- int flags, size, op;
- { struct amode *ap;
- ap = gen_expr(node->v.p[0],F_DREG | F_VOL,size);
- gen_code(op,size,ap,0);
- make_legal(ap,flags,size);
- return ap;
- }
-
- struct amode *gen_binary(node,flags,size,op)
- /*
- * generate code to evaluate a binary node and return
- * the addressing mode of the result.
- */
- struct enode *node;
- int flags, size, op;
- { struct amode *ap1, *ap2;
- ap1 = gen_expr(node->v.p[0],F_VOL | F_DREG | F_AREG,size);
- ap2 = gen_expr(node->v.p[1],F_ALL,size);
- validate(ap1); /* in case push occurred */
- gen_code(op,size,ap2,ap1);
- freeop(ap2);
- make_legal(ap1,flags,size);
- return ap1;
- }
-
- struct amode *gen_xbin(node,flags,size,op)
- /*
- * generate code to evaluate a restricted binary node and return
- * the addressing mode of the result.
- */
- struct enode *node;
- int flags, size, op;
- { struct amode *ap1, *ap2;
- ap1 = gen_expr(node->v.p[0],F_VOL | F_DREG,size);
- ap2 = gen_expr(node->v.p[1],F_DREG,size);
- validate(ap1); /* in case push occurred */
- gen_code(op,size,ap2,ap1);
- freeop(ap2);
- make_legal(ap1,flags,size);
- return ap1;
- }
- struct amode *gen_shift(node,flags,size,op)
- /*
- * generate code to evaluate a shift node and return the
- * address mode of the result.
- */
- struct enode *node;
- int flags, size, op;
- { struct amode *ap1, *ap2;
- ap1 = gen_expr(node->v.p[0],F_DREG | F_VOL,size);
- ap2 = gen_expr(node->v.p[1],F_DREG | F_IMMED,1);
- validate(ap1);
- gen_code(op,size,ap2,ap1);
- freeop(ap2);
- make_legal(ap1,flags,size);
- return ap1;
- }
-
- struct amode *gen_modiv(node,flags,size,op,modflag)
- /*
- * generate code to evaluate a mod operator or a divide
- * operator. these operations are done on only long
- * divisors and word dividends so that the 68000 div
- * instruction can be used.
- */
- struct enode *node;
- int flags, op, size, modflag;
- { struct amode *ap1, *ap2;
- if( node->v.p[0]->nodetype == en_icon )
- swap_nodes(node);
- ap1 = gen_expr(node->v.p[0],F_DREG | F_VOL,4);
- ap2 = gen_expr(node->v.p[1],F_ALL,2);
- validate(ap1);
- gen_code(op,0,ap2,ap1);
- if( modflag )
- gen_code(op_swap,0,ap1,0);
- gen_code(op_ext,4,ap1,0);
- make_legal(ap1,flags,4);
- freeop(ap2);
- return ap1;
- }
-
- swap_nodes(node)
- /*
- * exchange the two operands in a node.
- */
- struct enode *node;
- { struct enode *temp;
- temp = node->v.p[0];
- node->v.p[0] = node->v.p[1];
- node->v.p[1] = temp;
- }
-
- struct amode *gen_mul(node,flags,size,op)
- /*
- * generate code to evaluate a multiply node. both operands
- * are treated as words and the result is long and is always
- * in a register so that the 68000 mul instruction can be used.
- */
- struct enode *node;
- int flags, size, op;
- { struct amode *ap1, *ap2;
- if( node->v.p[0]->nodetype == en_icon )
- swap_nodes(node);
- ap1 = gen_expr(node->v.p[0],F_DREG | F_VOL,2);
- ap2 = gen_expr(node->v.p[1],F_ALL,2);
- validate(ap1);
- gen_code(op,0,ap2,ap1);
- freeop(ap2);
- make_legal(ap1,flags,4);
- return ap1;
- }
-
- struct amode *gen_hook(node,flags,size)
- /*
- * generate code to evaluate a condition operator node (?:)
- */
- struct enode *node;
- int flags, size;
- { struct amode *ap1, *ap2;
- int false_label, end_label;
- false_label = nextlabel++;
- end_label = nextlabel++;
- flags = (flags & (F_AREG | F_DREG)) | F_VOL;
- falsejp(node->v.p[0],false_label);
- node = node->v.p[1];
- ap1 = gen_expr(node->v.p[0],flags,size);
- freeop(ap1);
- gen_code(op_bra,0,make_label(end_label),0);
- gen_label(false_label);
- ap2 = gen_expr(node->v.p[1],flags,size);
- if( !equal_address(ap1,ap2) )
- {
- freeop(ap2);
- if( ap1->mode == am_dreg )
- temp_data();
- else
- temp_addr();
- gen_code(op_move,size,ap2,ap1);
- }
- gen_label(end_label);
- return ap1;
- }
-
- struct amode *gen_asadd(node,flags,size,op)
- /*
- * generate a plus equal or a minus equal node.
- */
- struct enode *node;
- int flags,size,op;
- { struct amode *ap1, *ap2;
- int ssize, mask0, mask1;
- ssize = natural_size(node->v.p[0]);
- if( ssize > size )
- size = ssize;
- ap1 = gen_expr(node->v.p[0],F_ALL,ssize);
- ap2 = gen_expr(node->v.p[1],F_DREG | F_AREG | F_IMMED,size);
- validate(ap1);
- gen_code(op,ssize,ap2,ap1);
- freeop(ap2);
- do_extend(ap1,ssize,size);
- make_legal(ap1,flags,size);
- return ap1;
- }
-
- struct amode *gen_aslogic(node,flags,size,op)
- /*
- * generate a and equal or a or equal node.
- */
- struct enode *node;
- int flags,size,op;
- { struct amode *ap1, *ap2, *ap3;
- int ssize, mask0, mask1;
- ssize = natural_size(node->v.p[0]);
- if( ssize > size )
- size = ssize;
- ap1 = gen_expr(node->v.p[0],F_ALL,ssize);
- ap2 = gen_expr(node->v.p[1],F_DREG | F_IMMED,size);
- validate(ap1);
- if( ap1->mode != am_areg )
- gen_code(op,ssize,ap2,ap1);
- else
- {
- ap3 = temp_data();
- gen_code(op_move,4,ap1,ap3);
- gen_code(op,size,ap2,ap3);
- gen_code(op_move,size,ap3,ap1);
- freeop(ap3);
- }
- freeop(ap2);
- do_extend(ap1,ssize,size);
- make_legal(ap1,flags,size);
- return ap1;
- }
-
- gen_asshift(node,flags,size,op)
- /*
- * generate shift equals operators.
- */
- struct enode *node;
- int flags, size, op;
- { struct amode *ap1, *ap2, *ap3;
- ap1 = gen_expr(node->v.p[0],F_ALL,size);
- if( ap1->mode != am_dreg )
- {
- ap3 = temp_data();
- gen_code(op_move,size,ap1,ap3);
- }
- else
- ap3 = ap1;
- ap2 = gen_expr(node->v.p[1],F_DREG | F_IMMED,size);
- validate(ap3);
- gen_code(op,size,ap2,ap3);
- freeop(ap2);
- if( ap3 != ap1 )
- {
- gen_code(op_move,size,ap3,ap1);
- freeop(ap3);
- }
- make_legal(ap1,flags,size);
- return ap1;
- }
-
- struct amode *gen_asmul(node,flags,size)
- /*
- * generate a *= node.
- */
- struct enode *node;
- int flags, size;
- { struct amode *ap1, *ap2, *ap3;
- int siz1;
- siz1 = natural_size(node->v.p[0]);
- ap1 = gen_expr(node->v.p[1],F_DREG | F_VOL,2);
- ap2 = gen_expr(node->v.p[0],F_ALL,siz1);
- if( siz1 == 1 || ap2->mode == am_areg )
- {
- ap3 = temp_data();
- gen_code(op_move,siz1,ap2,ap3);
- if( siz1 == 1 )
- gen_code(op_ext,2,ap3,0);
- freeop(ap3);
- }
- else
- ap3 = ap2;
- gen_code(op_muls,0,ap3,ap1);
- gen_code(op_move,siz1,ap1,ap2);
- freeop(ap2);
- return ap1;
- }
-
- struct amode *gen_asmodiv(node,flags,size,op)
- /*
- * generate /= and %= nodes.
- */
- struct enode *node;
- int flags, size, op;
- { struct amode *ap1, *ap2, *ap3;
- int siz1;
- siz1 = natural_size(node->v.p[0]);
- ap1 = temp_data();
- ap2 = gen_expr(node->v.p[0],F_ALL,siz1);
- validate(ap1);
- gen_code(op_move,siz1,ap2,ap1);
- do_extend(ap1,siz1,4);
- ap3 = gen_expr(node->v.p[1],F_ALL & ~F_AREG,2);
- validate(ap2);
- validate(ap1);
- gen_code(op_divs,0,ap3,ap1);
- freeop(ap3);
- if( op != op_divs )
- gen_code(op_swap,0,ap1,0);
- gen_code(op_ext,4,ap1,0);
- gen_code(op_move,siz1,ap1,ap2);
- freeop(ap2);
- make_legal(ap1,flags,size);
- return ap1;
- }
-
- struct amode *gen_assign(node,flags,size)
- /*
- * generate code for an assignment node. if the size of the
- * assignment destination is larger than the size passed then
- * everything below this node will be evaluated with the
- * assignment size.
- */
- struct enode *node;
- int flags, size;
- { struct amode *ap1, *ap2;
- int ssize;
- switch( node->v.p[0]->nodetype )
- {
- case en_b_ref:
- ssize = 1;
- break;
- case en_w_ref:
- ssize = 2;
- break;
- case en_l_ref:
- case en_tempref:
- ssize = 4;
- break;
- }
- if( ssize > size )
- size = ssize;
- ap2 = gen_expr(node->v.p[1],F_ALL,size);
- ap1 = gen_expr(node->v.p[0],F_ALL,ssize);
- validate(ap2);
- gen_code(op_move,ssize,ap2,ap1);
- freeop(ap1);
- return ap2;
- }
-
- struct amode *gen_aincdec(node,flags,size,op)
- /*
- * generate an auto increment or decrement node. op should be
- * either op_add (for increment) or op_sub (for decrement).
- */
- struct enode *node;
- int flags, size;
- { struct amode *ap1, *ap2;
- int siz1;
- siz1 = natural_size(node->v.p[0]);
- if( flags & F_NOVALUE ) /* dont need result */
- {
- ap1 = gen_expr(node->v.p[0],F_ALL,siz1);
- gen_code(op,siz1,make_immed(node->v.p[1]),ap1);
- freeop(ap1);
- return ap1;
- }
- if( flags & F_DREG )
- ap1 = temp_data();
- else
- ap1 = temp_addr();
- ap2 = gen_expr(node->v.p[0],F_ALL,siz1);
- validate(ap1);
- gen_code(op_move,siz1,ap2,ap1);
- gen_code(op,siz1,make_immed(node->v.p[1]),ap2);
- freeop(ap2);
- do_extend(ap1,siz1,size);
- return ap1;
- }
-
- push_param(ep)
- /*
- * push the operand expression onto the stack.
- */
- struct enode *ep;
- { struct amode *ap;
- ap = gen_expr(ep,F_ALL,4);
- gen_code(op_move,4,ap,push);
- freeop(ap);
- }
-
- int gen_parms(plist)
- /*
- * push a list of parameters onto the stack and return the
- * number of parameters pushed.
- */
- struct enode *plist;
- { int i;
- i = 0;
- while( plist != 0 )
- {
- push_param(plist->v.p[0]);
- plist = plist->v.p[1];
- ++i;
- }
- return i;
- }
-
- struct amode *gen_fcall(node,flags)
- /*
- * generate a function call node and return the address mode
- * of the result.
- */
- struct enode *node;
- { struct amode *ap, *result;
- int i;
- result = temp_addr();
- temp_addr(); /* push any used addr temps */
- freeop(result); freeop(result);
- result = temp_data();
- temp_data(); temp_data(); /* push any used data registers */
- freeop(result); freeop(result); freeop(result);
- i = gen_parms(node->v.p[1]); /* generate parameters */
- if( node->v.p[0]->nodetype == en_nacon )
- gen_code(op_jsr,0,make_offset(node->v.p[0]),0);
- else
- {
- ap = gen_expr(node->v.p[0],F_AREG,4);
- ap->mode = am_ind;
- freeop(ap);
- gen_code(op_jsr,0,ap,0);
- }
- if( i != 0 )
- gen_code(op_add,4,make_immed(i * 4),makeareg(7));
- if( flags & F_DREG )
- result = temp_data();
- else
- result = temp_addr();
- if( result->preg != 0 || (flags & F_DREG) == 0 )
- gen_code(op_move,4,makedreg(0),result);
- return result;
- }
-
- struct amode *gen_expr(node,flags,size)
- /*
- * general expression evaluation. returns the addressing mode
- * of the result.
- */
- struct enode *node;
- int flags, size;
- { struct amode *ap1, *ap2;
- int lab0, lab1;
- int natsize;
- if( node == 0 )
- {
- printf("DIAG - null node in gen_expr.\n");
- return 0;
- }
- switch( node->nodetype )
- {
- case en_icon:
- case en_labcon:
- case en_nacon:
- ap1 = xalloc(sizeof(struct amode));
- ap1->mode = am_immed;
- ap1->offset = node;
- make_legal(ap1,flags,size);
- return ap1;
- case en_autocon:
- ap1 = temp_addr();
- ap2 = xalloc(sizeof(struct amode));
- ap2->mode = am_indx;
- ap2->preg = 6; /* frame pointer */
- ap2->offset = node; /* use as constant node */
- gen_code(op_lea,0,ap2,ap1);
- make_legal(ap1,flags,size);
- return ap1; /* return reg */
- case en_b_ref:
- case en_w_ref:
- case en_l_ref:
- return gen_deref(node,flags,size);
- case en_tempref:
- ap1 = xalloc(sizeof(struct amode));
- if( node->v.i < 8 )
- {
- ap1->mode = am_dreg;
- ap1->preg = node->v.i;
- }
- else
- {
- ap1->mode = am_areg;
- ap1->preg = node->v.i - 8;
- }
- ap1->tempflag = 0; /* not a temporary */
- make_legal(ap1,flags,size);
- return ap1;
- case en_uminus:
- return gen_unary(node,flags,size,op_neg);
- case en_compl:
- return gen_unary(node,flags,size,op_not);
- case en_add:
- return gen_binary(node,flags,size,op_add);
- case en_sub:
- return gen_binary(node,flags,size,op_sub);
- case en_and:
- return gen_binary(node,flags,size,op_and);
- case en_or:
- return gen_binary(node,flags,size,op_or);
- case en_xor:
- return gen_xbin(node,flags,size,op_eor);
- case en_mul:
- return gen_mul(node,flags,size,op_muls);
- case en_umul:
- return gen_mul(node,flags,size,op_mulu);
- case en_div:
- return gen_modiv(node,flags,size,op_divs,0);
- case en_udiv:
- return gen_modiv(node,flags,size,op_divu,0);
- case en_mod:
- return gen_modiv(node,flags,size,op_divs,1);
- case en_umod:
- return gen_modiv(node,flags,size,op_divu,1);
- case en_lsh:
- return gen_shift(node,flags,size,op_asl);
- case en_rsh:
- return gen_shift(node,flags,size,op_asr);
- case en_asadd:
- return gen_asadd(node,flags,size,op_add);
- case en_assub:
- return gen_asadd(node,flags,size,op_sub);
- case en_asand:
- return gen_aslogic(node,flags,size,op_and);
- case en_asor:
- return gen_aslogic(node,flags,size,op_or);
- case en_aslsh:
- return gen_asshift(node,flags,size,op_asl);
- case en_asrsh:
- return gen_asshift(node,flags,size,op_asr);
- case en_asmul:
- return gen_asmul(node,flags,size);
- case en_asdiv:
- return gen_asmodiv(node,flags,size,op_divs);
- case en_asmod:
- return gen_asmodiv(node,flags,size,op_muls);
- case en_assign:
- return gen_assign(node,flags,size);
- case en_ainc:
- return gen_aincdec(node,flags,size,op_add);
- case en_adec:
- return gen_aincdec(node,flags,size,op_sub);
- case en_land: case en_lor:
- case en_eq: case en_ne:
- case en_lt: case en_le:
- case en_gt: case en_ge:
- case en_ult: case en_ule:
- case en_ugt: case en_uge:
- case en_not:
- lab0 = nextlabel++;
- lab1 = nextlabel++;
- falsejp(node,lab0);
- ap1 = temp_data();
- gen_code(op_moveq,0,make_immed(1),ap1);
- gen_code(op_bra,0,make_label(lab1),0);
- gen_label(lab0);
- gen_code(op_clr,4,ap1,0);
- gen_label(lab1);
- return ap1;
- case en_cond:
- return gen_hook(node,flags,size);
- case en_void:
- natsize = natural_size(node->v.p[0]);
- freeop(gen_expr(node->v.p[0],F_ALL | F_NOVALUE,natsize));
- return gen_expr(node->v.p[1],flags,size);
- case en_fcall:
- return gen_fcall(node,flags);
- default:
- printf("DIAG - uncoded node in gen_expr.\n");
- return 0;
- }
- }
-
- int natural_size(node)
- /*
- * return the natural evaluation size of a node.
- */
- struct enode *node;
- { int siz0, siz1;
- if( node == 0 )
- return 0;
- switch( node->nodetype )
- {
- case en_icon:
- if( -128 <= node->v.i && node->v.i <= 127 )
- return 1;
- if( -32768 <= node->v.i && node->v.i <= 32767 )
- return 2;
- return 4;
- case en_fcall: case en_labcon:
- case en_nacon: case en_autocon:
- case en_l_ref: case en_tempref:
- case en_cbl: case en_cwl:
- return 4;
- case en_b_ref:
- return 1;
- case en_cbw:
- case en_w_ref:
- return 2;
- case en_not: case en_compl:
- case en_uminus: case en_assign:
- case en_ainc: case en_adec:
- return natural_size(node->v.p[0]);
- case en_add: case en_sub:
- case en_mul: case en_div:
- case en_mod: case en_and:
- case en_or: case en_xor:
- case en_lsh: case en_rsh:
- case en_eq: case en_ne:
- case en_lt: case en_le:
- case en_gt: case en_ge:
- case en_land: case en_lor:
- case en_asadd: case en_assub:
- case en_asmul: case en_asdiv:
- case en_asmod: case en_asand:
- case en_asor: case en_aslsh:
- case en_asrsh:
- siz0 = natural_size(node->v.p[0]);
- siz1 = natural_size(node->v.p[1]);
- if( siz1 > siz0 )
- return siz1;
- else
- return siz0;
- case en_void: case en_cond:
- return natural_size(node->v.p[1]);
- default:
- printf("DIAG - natural size error.\n");
- break;
- }
- return 0;
- }
-
- gen_compare(node)
- /*
- * generate code to do a comparison of the two operands of
- * node.
- */
- struct enode *node;
- { struct amode *ap1, *ap2;
- int size;
- size = natural_size(node);
- ap1 = gen_expr(node->v.p[0],F_AREG | F_DREG, size);
- ap2 = gen_expr(node->v.p[1],F_ALL,size);
- validate(ap1);
- gen_code(op_cmp,size,ap2,ap1);
- freeop(ap2);
- freeop(ap1);
- }
-
- truejp(node,label)
- /*
- * generate a jump to label if the node passed evaluates to
- * a true condition.
- */
- struct enode *node;
- int label;
- { struct amode *ap1;
- int siz1;
- int lab0;
- if( node == 0 )
- return;
- switch( node->nodetype )
- {
- case en_eq:
- gen_compare(node);
- gen_code(op_beq,0,make_label(label),0);
- break;
- case en_ne:
- gen_compare(node);
- gen_code(op_bne,0,make_label(label),0);
- break;
- case en_lt:
- gen_compare(node);
- gen_code(op_blt,0,make_label(label),0);
- break;
- case en_le:
- gen_compare(node);
- gen_code(op_ble,0,make_label(label),0);
- break;
- case en_gt:
- gen_compare(node);
- gen_code(op_bgt,0,make_label(label),0);
- break;
- case en_ge:
- gen_compare(node);
- gen_code(op_bge,0,make_label(label),0);
- break;
- case en_ult:
- gen_compare(node);
- gen_code(op_blo,0,make_label(label),0);
- break;
- case en_ule:
- gen_compare(node);
- gen_code(op_bls,0,make_label(label),0);
- break;
- case en_ugt:
- gen_compare(node);
- gen_code(op_bhi,0,make_label(label),0);
- break;
- case en_uge:
- gen_compare(node);
- gen_code(op_bhs,0,make_label(label),0);
- break;
- case en_land:
- lab0 = nextlabel++;
- falsejp(node->v.p[0],lab0);
- truejp(node->v.p[1],label);
- gen_label(lab0);
- break;
- case en_lor:
- truejp(node->v.p[0],label);
- truejp(node->v.p[1],label);
- break;
- case en_not:
- falsejp(node->v.p[0],label);
- break;
- default:
- siz1 = natural_size(node);
- ap1 = gen_expr(node,F_ALL,siz1);
- gen_code(op_tst,siz1,ap1,0);
- freeop(ap1);
- gen_code(op_bne,0,make_label(label),0);
- break;
- }
- }
-
- falsejp(node,label)
- /*
- * generate code to execute a jump to label if the expression
- * passed is false.
- */
- struct enode *node;
- int label;
- { struct amode *ap;
- int siz1;
- int lab0;
- if( node == 0 )
- return;
- switch( node->nodetype )
- {
- case en_eq:
- gen_compare(node);
- gen_code(op_bne,0,make_label(label),0);
- break;
- case en_ne:
- gen_compare(node);
- gen_code(op_beq,0,make_label(label),0);
- break;
- case en_lt:
- gen_compare(node);
- gen_code(op_bge,0,make_label(label),0);
- break;
- case en_le:
- gen_compare(node);
- gen_code(op_bgt,0,make_label(label),0);
- break;
- case en_gt:
- gen_compare(node);
- gen_code(op_ble,0,make_label(label),0);
- break;
- case en_ge:
- gen_compare(node);
- gen_code(op_blt,0,make_label(label),0);
- break;
- case en_ult:
- gen_compare(node);
- gen_code(op_bhs,0,make_label(label),0);
- break;
- case en_ule:
- gen_compare(node);
- gen_code(op_bhi,0,make_label(label),0);
- break;
- case en_ugt:
- gen_compare(node);
- gen_code(op_bls,0,make_label(label),0);
- break;
- case en_uge:
- gen_compare(node);
- gen_code(op_blo,0,make_label(label),0);
- break;
- case en_land:
- falsejp(node->v.p[0],label);
- falsejp(node->v.p[1],label);
- break;
- case en_lor:
- lab0 = nextlabel++;
- truejp(node->v.p[0],lab0);
- falsejp(node->v.p[1],label);
- gen_label(lab0);
- break;
- case en_not:
- truejp(node->v.p[0],label);
- break;
- default:
- siz1 = natural_size(node);
- ap = gen_expr(node,F_ALL,siz1);
- gen_code(op_tst,siz1,ap,0);
- freeop(ap);
- gen_code(op_beq,0,make_label(label),0);
- break;
- }
- }
-